export class MonacoInlineCompletionProvider {
  constructor(monaco) {
    this.monaco = monaco;
    this.debounceTimeout = null;
    this.lastTypedText = "";
    this.DEBOUNCE_DELAY = 1000;
    this.currentRequest = null;
    this.projectFiles = new Map(); // 存储项目文件信息

    // 添加请求限制相关的属性
    this.requestCount = 0; // 请求计数
    this.requestTimestamp = Date.now(); // 请求时间戳
    this.REQUEST_LIMIT = 20; // 每分钟最大请求次数
    this.REQUEST_WINDOW = 60000; // 时间窗口（1分钟）
  }

  // 分析当前文件的导入语句
  analyzeImports(fileContent) {
    const imports = [];
    const importRegex =
      /import\s+(?:{[^}]+}|\*\s+as\s+\w+|\w+)\s+from\s+['"]([^'"]+)['"]/g;
    let match;

    while ((match = importRegex.exec(fileContent)) !== null) {
      imports.push(match[1]);
    }

    return imports;
  }

  // 获取相关文件的内容
  async getRelatedFiles(model) {
    const currentUri = model.uri.toString();
    // 只有当不是内存模型时才添加当前文件
    const relatedFiles = new Map();
    if (!currentUri.startsWith("inmemory://")) {
      const currentContent = model.getValue();
      const imports = this.analyzeImports(currentContent);
      relatedFiles.set(currentUri, {
        content: currentContent,
        imports: imports,
      });
    }

    // 获取所有打开的编辑器模型
    const models = this.monaco.editor.getModels();

    for (const m of models) {
      const uri = m.uri.toString();
      // 跳过内存模型和当前文件
      if (!uri.startsWith("inmemory://") && uri !== currentUri) {
        const content = m.getValue();
        const fileImports = this.analyzeImports(content);
        relatedFiles.set(uri, {
          content: content,
          imports: fileImports,
        });
      }
    }

    return relatedFiles;
  }

  // 提取JSDoc注释
  extractJSDoc(content, position) {
    // 向上查找最近的JSDoc注释
    const lines = content.slice(0, position).split("\n");
    let jsdoc = "";
    let lineIndex = lines.length - 1;
    let foundJSDoc = false;

    // 跳过空行
    while (lineIndex >= 0 && lines[lineIndex].trim() === "") {
      lineIndex--;
    }

    // 收集JSDoc注释
    while (lineIndex >= 0) {
      const line = lines[lineIndex].trim();
      if (line.endsWith("*/")) {
        foundJSDoc = true;
        jsdoc = line + "\n" + jsdoc;
      } else if (line.startsWith("/*") || line.startsWith("*")) {
        jsdoc = line + "\n" + jsdoc;
        if (line.startsWith("/*")) {
          break;
        }
      } else if (foundJSDoc) {
        break;
      } else {
        break;
      }
      lineIndex--;
    }

    return jsdoc.trim();
  }

  // 分析导出语句
  analyzeExports(content) {
    const exports = new Set();

    // 检查是否是 .d.ts 文件
    const isDtsFile = content.includes("declare ") || /\.d\.ts$/.test(content);

    // 匹配 export 语句
    const exportPatterns = [
      // export class/function/const/let/var/type/interface
      /export\s+(?:default\s+)?(?:class|function|const|let|var|type|interface)\s+(\w+)/g,
      // export { name1, name2 }
      /export\s*{([^}]+)}/g,
      // export default identifier
      /export\s+default\s+(\w+)/g,
      // module.exports = { name1, name2 }
      /module\.exports\s*=\s*{([^}]+)}/g,
      // module.exports.name =
      /module\.exports\.(\w+)\s*=/g,
      // exports.name =
      /exports\.(\w+)\s*=/g,
    ];

    // 如果是 .d.ts 文件，添加额外的声明模式
    if (isDtsFile) {
      exportPatterns.push(
        // declare class/interface/type/function
        /declare\s+(?:class|interface|type|function)\s+(\w+)/g,
        // declare module
        /declare\s+module\s+['"]([^'"]+)['"]/g,
        // declare namespace
        /declare\s+namespace\s+(\w+)/g,
        // declare const/let/var
        /declare\s+(?:const|let|var)\s+(\w+)/g
      );
    }

    // 处理 export { name1, name2 } 和 module.exports = { name1, name2 } 的情况
    const processExportObject = (match) => {
      const names = match.split(",").map((name) => {
        // 处理 as 语法: originalName as exportName
        const asMatch = name.match(/(\w+)\s+as\s+(\w+)/);
        if (asMatch) {
          return asMatch[1].trim();
        }
        return name.trim();
      });
      names.forEach((name) => exports.add(name));
    };

    for (const pattern of exportPatterns) {
      let match;
      while ((match = pattern.exec(content)) !== null) {
        if (pattern.toString().includes("{([^}]+)}")) {
          // 处理导出对象
          processExportObject(match[1]);
        } else {
          // 处理直接导出
          const exportName = match[1];
          if (exportName) {
            exports.add(exportName);
          }
        }
      }
    }

    return exports;
  }

  // 分析函数定义
  analyzeFunctionDefinition(content) {
    // 使用 Map 来存储函数，键为函数签名
    const functionMap = new Map();

    // 获取所有导出的标识符
    const exports = this.analyzeExports(content);

    // 匹配函数声明、箭头函数、类方法等
    const functionPatterns = [
      // 普通函数声明
      /(?:async\s+)?function\s+(\w+)\s*\((.*?)\)/g,
      // 箭头函数赋值
      /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\((.*?)\)\s*=>/g,
      // 对象方法
      /(\w+)\s*:\s*(?:async\s*)?\((.*?)\)\s*(?:=>|{)/g,
      // 类方法
      /(?:async\s+)?(\w+)\s*\((.*?)\)\s*{/g,
    ];

    const seenLocations = new Set(); // 用于记录已处理的位置

    for (const pattern of functionPatterns) {
      let match;
      while ((match = pattern.exec(content)) !== null) {
        const [fullMatch, name, params = ""] = match;

        // 检查这个位置是否已经处理过
        const location = `${match.index}-${match.index + fullMatch.length}`;
        if (seenLocations.has(location)) {
          continue;
        }
        seenLocations.add(location);

        if (name && !name.match(/^(if|for|while|switch)$/)) {
          // 排除控制结构
          const paramList = params
            .split(",")
            .map((p) => p.trim())
            .filter((p) => p)
            .map((p) => {
              const [paramName, defaultValue] = p
                .split("=")
                .map((s) => s.trim());
              const typeMatch = paramName.match(/(.*?)\s*:\s*(.*)/); // 处理可能的类型注解
              return {
                name: typeMatch ? typeMatch[1] : paramName,
                type: typeMatch ? typeMatch[2] : undefined,
                default: defaultValue || undefined,
              };
            });

          // 创建函数签名（用于去重）
          const signature = `${name}(${paramList
            .map((p) => p.name)
            .join(", ")})`;

          // 只有当这个签名不存在时才添加
          // 只添加被导出的函数
          if (!functionMap.has(signature) && exports.has(name)) {
            // 提取JSDoc注释
            const jsdoc = this.extractJSDoc(content, match.index);

            functionMap.set(signature, {
              type: "function",
              name,
              params: paramList,
              isAsync: fullMatch.includes("async"),
              jsdoc: jsdoc || undefined,
              location: {
                start: match.index,
                end: match.index + fullMatch.length,
              },
            });
          }
        }
      }
    }

    // 返回去重后的函数数组
    return Array.from(functionMap.values());
  }

  // 分析类定义
  analyzeClassDefinition(content) {
    const classes = [];
    const classRegex =
      /(?:declare\s+)?class\s+(\w+)(?:\s+extends\s+(\w+))?\s*{([^}]*)}/gs;

    // 获取所有导出的标识符
    const exports = this.analyzeExports(content);

    let match;
    while ((match = classRegex.exec(content)) !== null) {
      const [fullMatch, className, extends_, classBody] = match;

      // 检查是否是 .d.ts 文件
      const isDtsFile =
        content.includes("declare ") || /\.d\.ts$/.test(content);

      // 只处理被导出的类或在 .d.ts 文件中声明的类
      if (!exports.has(className) && !isDtsFile) {
        continue;
      }

      // 分析类的方法
      const methods = this.analyzeFunctionDefinition(classBody);

      // 分析类的属性
      const propertyRegex = /(\w+)\s*(?::\s*\w+)?(?:=|;)/g;
      const properties = [];
      let propertyMatch;
      while ((propertyMatch = propertyRegex.exec(classBody)) !== null) {
        const [_, propName] = propertyMatch;
        if (!methods.some((m) => m.name === propName)) {
          // 确保不是方法
          properties.push({
            name: propName,
          });
        }
      }

      // 提取类的JSDoc注释
      const classJsdoc = this.extractJSDoc(content, match.index);

      classes.push({
        type: "class",
        name: className,
        extends: extends_,
        methods,
        properties,
        jsdoc: classJsdoc || undefined,
        location: {
          start: match.index,
          end: match.index + fullMatch.length,
        },
      });
    }

    return classes;
  }

  // 分析工程上下文
  async analyzeProjectContext(model) {
    const relatedFiles = await this.getRelatedFiles(model);
    const currentUri = model.uri.toString();
    const currentFile = relatedFiles.get(currentUri);

    // 构建项目上下文信息
    let projectContext = "";

    // 添加当前文件的导入信息（如果不是内存模型）
    if (
      !currentUri.startsWith("inmemory://") &&
      currentFile.imports.length > 0
    ) {
      projectContext +=
        "\n相关导入:\n" +
        currentFile.imports.map((imp) => `- ${imp}`).join("\n");
    }

    // 分析所有相关文件
    for (const [uri, fileInfo] of relatedFiles) {
      // 跳过内存模型文件
      if (uri.startsWith("inmemory://")) {
        continue;
      }
      projectContext += `\n\n文件: ${uri}`;

      // 分析函数定义
      const functions = this.analyzeFunctionDefinition(fileInfo.content);
      if (functions.length > 0) {
        projectContext += "\n函数定义:";
        for (const func of functions) {
          const params = func.params
            .map((p) => {
              let paramStr = p.name;
              if (p.type) paramStr += `: ${p.type}`;
              if (p.default) paramStr += ` = ${p.default}`;
              return paramStr;
            })
            .join(", ");

          // 添加JSDoc注释（如果存在）
          if (func.jsdoc) {
            projectContext += `\n${func.jsdoc}`;
          }
          projectContext += `\n- ${func.isAsync ? "async " : ""}${
            func.name
          }(${params})`;
        }
      }

      // 分析类定义
      const classes = this.analyzeClassDefinition(fileInfo.content);
      if (classes.length > 0) {
        projectContext += "\n类定义:";
        for (const cls of classes) {
          // 添加类的JSDoc注释（如果存在）
          if (cls.jsdoc) {
            projectContext += `\n${cls.jsdoc}`;
          }
          projectContext += `\n- class ${cls.name}${
            cls.extends ? ` extends ${cls.extends}` : ""
          }`;

          if (cls.properties.length > 0) {
            projectContext += "\n  属性:";
            for (const prop of cls.properties) {
              projectContext += `\n    - ${prop.name}`;
            }
          }

          if (cls.methods.length > 0) {
            projectContext += "\n  方法:";
            for (const method of cls.methods) {
              const params = method.params
                .map((p) => {
                  let paramStr = p.name;
                  if (p.type) paramStr += `: ${p.type}`;
                  if (p.default) paramStr += ` = ${p.default}`;
                  return paramStr;
                })
                .join(", ");

              projectContext += `\n    - ${method.isAsync ? "async " : ""}${
                method.name
              }(${params})`;
            }
          }
        }
      }
    }

    return projectContext;
  }

  // 实现必需的 freeInlineCompletions 方法
  freeInlineCompletions(completions) {
    // Monaco editor will call this method when completions are no longer needed
    if (this.debounceTimeout) {
      clearTimeout(this.debounceTimeout);
      this.debounceTimeout = null;
    }
    this.cancelCurrentRequest();
  }

  parseInlineBlocks(response) {
    const blocks = [];
    const regex =
      /<Inline(?:\s+range=\(\((\d+),\s*(\d+)\),\s*\((\d+),\s*(\d+)\)\))?>([^<]*)<\/Inline>/gs;
    let match;

    const originalString = response;
    let stringToRemove = "```javascript";

    let result = originalString.replace(new RegExp(stringToRemove, "g"), "");
    stringToRemove = "```js";
    result = result.replace(new RegExp(stringToRemove, "g"), "");
    stringToRemove = "```";
    result = result.replace(new RegExp(stringToRemove, "g"), "");

    while ((match = regex.exec(response)) !== null) {
      const [_, startLine, startChar, endLine, endChar, content] = match;
      // Remove markdown code block syntax
      // 先尝试匹配 markdown 代码块
      let cleanContent = content;

      // 清理其他标记
      cleanContent = cleanContent
        .replace(
          /<Inline(?:\s+range=\(\((\d+),\s*(\d+)\),\s*\((\d+),\s*(\d+)\)\))?>([^<]*)<\/Inline>/g,
          "$1"
        )
        .trim();

      // 只有当所有范围参数都存在时才创建范围
      let blockRange = undefined;
      if (startLine && startChar && endLine && endChar) {
        blockRange = new this.monaco.Range(
          parseInt(startLine),
          parseInt(startChar),
          parseInt(endLine),
          parseInt(endChar)
        );
      }

      const block = {
        text: cleanContent,
        range: blockRange,
      };

      if (block.text) {
        blocks.push(block);
      }
    }

    return blocks;
  }

  getLineContext(model, position) {
    const currentLine = model.getLineContent(position.lineNumber);
    const currentLinePrefix = currentLine.substring(0, position.column - 1);
    const currentLineSuffix = currentLine.substring(position.column - 1);

    // 获取当前行的缩进
    const indentation = currentLinePrefix.match(/^\s*/)?.[0] || "";

    // 分析当前行的语法结构
    const openBrackets = (currentLinePrefix.match(/[({[]/g) || []).length;
    const closeBrackets = (currentLinePrefix.match(/[)}\]]/g) || []).length;

    let beforeLines = 200; // 获取更多上下文
    let afterLines = 200;

    // 获取前面几行代码
    const startLine = Math.max(1, position.lineNumber - beforeLines);
    const beforeCursor =
      position.lineNumber > startLine
        ? model.getValueInRange(
            new this.monaco.Range(startLine, 1, position.lineNumber, 1)
          )
        : "";

    // 获取后面几行代码
    const endLine = Math.min(
      model.getLineCount(),
      position.lineNumber + afterLines
    );
    const afterCursor =
      position.lineNumber < endLine
        ? model.getValueInRange(
            new this.monaco.Range(
              position.lineNumber + 1,
              1,
              endLine,
              model.getLineMaxColumn(endLine)
            )
          )
        : "";

    // 分析代码结构
    const codeStructure = {
      isInFunction:
        beforeCursor.includes("function") || beforeCursor.includes("=>"),
      isInClass: beforeCursor.includes("class"),
      isInObject:
        openBrackets > closeBrackets && currentLinePrefix.includes("{"),
      indentationLevel: indentation.length,
    };

    // 获取从上文开始到下文结束的完整Range
    const currentRange = new this.monaco.Range(
      startLine,
      1,
      endLine,
      model.getLineMaxColumn(endLine)
    );
    return {
      beforeCursor,
      afterCursor,
      currentLinePrefix,
      currentLineSuffix,
      indentation,
      currentRange,
      codeStructure,
    };
  }

  cancelCurrentRequest() {
    if (this.currentRequest) {
      this.currentRequest.abort();
      this.currentRequest = null;
    }
  }

  // 检查是否超出请求限制
  checkRequestLimit() {
    const now = Date.now();

    // 如果已经过了一分钟，重置计数器
    if (now - this.requestTimestamp >= this.REQUEST_WINDOW) {
      this.requestCount = 0;
      this.requestTimestamp = now;
      return true;
    }

    // 如果在一分钟内且未超出限制
    if (this.requestCount < this.REQUEST_LIMIT) {
      this.requestCount++;
      return true;
    }

    // 超出限制
    return false;
  }

  async getAICompletions(prompt, q, range, currentLinePrefix) {
    const completions = [];
    console.log("getAICompletions");

    try {
      this.cancelCurrentRequest();
      this.currentRequest = new AbortController();

      const aiResponse = await handleCreateChatNonStream({
        checkRequestLimit: this.checkRequestLimit(),
        prompt,
        q,
      });

      if (this.currentRequest?.signal.aborted) {
        return [];
      }

      if (!aiResponse) {
        return completions;
      }

      const codeBlocks = this.parseInlineBlocks(aiResponse);

      for (const block of codeBlocks) {
        // 只有当没有指定范围时才使用光标位置的范围
        completions.push({
          insertText: block.text,
          range: block.range === undefined ? range : block.range,
        });
      }

      if (completions.length === 0 && aiResponse.trim()) {
        const response = aiResponse.trim();

        completions.push({
          insertText: response,
          range: range,
        });
      }
    } catch (error) {
      if (error instanceof Error && error.name === "AbortError") {
        console.log("Request was cancelled");
      } else {
        console.error("Error in getAICompletions:", error);
      }
    } finally {
      if (this.currentRequest?.signal.aborted) {
        this.currentRequest = null;
      }
    }
    console.log(completions);
    return completions;
  }

  async handleCompletion(model, position) {
    const context = this.getLineContext(model, position);
    const projectContext = await this.analyzeProjectContext(model);
    const range = new this.monaco.Range(
      position.lineNumber,
      position.column,
      position.lineNumber,
      model.getLineMaxColumn(position.lineNumber)
    );

    // 获取当前位置的TypeScript错误信息
    const markers = this.monaco.editor
      .getModelMarkers({
        resource: model.uri,
      })
      .filter((marker) => {
        // 只获取错误级别的标记
        return marker.severity === this.monaco.MarkerSeverity.Error;
      });

    // 构建错误信息字符串
    const errorInfo =
      markers.length > 0
        ? "\n\n当前JavaScript错误:\n" +
          markers
            .map(
              (marker) => `- 第${marker.startLineNumber}行: ${marker.message}`
            )
            .join("\n")
        : "";
    const prompt = `
请为以下javascript代码片段提供补全建议，仅返回光标位置（｜）后缺失的代码部分，并遵循以下规则：

补全规则
优先模仿光标位置附近的代码的意图和风格进行补全。
注释应该是中文的，最好使用jsdoc注释。
分析上下文的缩进、引号使用、命名风格等，并保持一致。
优先考虑上下文中已存在的相似模式、变量、函数或类型。
可提供多行补全，需保持正确的缩进。
补全应自然衔接当前输入，不要重复已输入内容
使用<Inline>标签包裹每个建议，按推荐度排序（最佳建议放首位）。
补全内容应自然衔接当前输入，避免重复已输入部分。
请确保变量名、函数名等代码在光标处作用域是可访问的，不要随意使用上下文中的代码。
你应该直接输出代码内容，不要输出任何解释，包括markdown代码块。

补全格式示例
简单补全
输入：console.log(\`Hello, ｜\`);
输出：
<Inline>world!</Inline>
<Inline>name</Inline>

多行补全
输入：function greet｜
输出：
<Inline>() {
  console.log('Hello, world!');
}</Inline>
<Inline>() {
  world.say("Hello");
}</Inline>

意图猜测
输入： dialog("介绍1")
｜
dialog("介绍3")
输出：
<Inline>dialog("介绍2")</Inline>
`;
    const q = `代码上下文信息：
- 代码范围：${context.currentRange}
- 是否在函数内：${context.codeStructure.isInFunction}
- 是否在类内：${context.codeStructure.isInClass}
- 是否在对象内：${context.codeStructure.isInObject}
- 缩进级别：${context.codeStructure.indentationLevel}
${errorInfo}

工程上下文信息：${projectContext}

上下文代码：
    ${context.beforeCursor}
${context.currentLinePrefix}｜${context.currentLineSuffix}
    ${context.afterCursor}`;

    const items = await this.getAICompletions(
      prompt,
      q,
      range,
      context.currentLinePrefix
    );

    return { items };
  }

  async provideInlineCompletions(model, position, context, token) {
    if (token.isCancellationRequested) {
      this.cancelCurrentRequest();
      return { items: [] };
    }

    const currentText = model.getLineContent(position.lineNumber);

    // 更新最后输入的文本
    this.lastTypedText = currentText;

    // 取消之前的请求和定时器
    this.cancelCurrentRequest();
    if (this.debounceTimeout) {
      clearTimeout(this.debounceTimeout);
    }

    // 返回一个 Promise，在防抖延迟后解析
    return new Promise((resolve) => {
      this.debounceTimeout = setTimeout(async () => {
        if (token.isCancellationRequested) {
          this.cancelCurrentRequest();
          resolve({ items: [] });
          return;
        }

        // 再次检查文本是否在等待期间发生变化
        const finalText = model.getLineContent(position.lineNumber);
        if (finalText !== this.lastTypedText) {
          this.cancelCurrentRequest();
          resolve({ items: [] });
          return;
        }

        try {
          const completions = await this.handleCompletion(model, position);

          resolve(completions);
        } catch (error) {
          console.error("Error in provideInlineCompletionItems:", error);
          resolve({ items: [] });
        }
      }, this.DEBOUNCE_DELAY);
    });
  }
}

// 注册内联补全提供程序
export function registerMonacoInlineCompletionProvider(monacoController) {
  const monaco = monacoController.monacoController.monaco;
  const provider = new MonacoInlineCompletionProvider(monaco);

  // 为所有语言注册提供程序
  const disposable = monaco.languages.registerInlineCompletionsProvider(
    { pattern: "**" },
    provider
  );

  return disposable;
}

// 非流式输出的聊天函数，用于内联补全
export async function handleCreateChatNonStream(message) {
  try {
    const resp = await fetch("https://api.siliconflow.cn/v1/chat/completions", {
      method: "POST",
      headers: {
        Authorization:
          "Bearer sk-oiduzzanqljdyqhcsjssgwxusbetmftkflqjjpcxtrldadlx",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        stream: false,
        model: message.checkRequestLimit
          ? "Qwen/Qwen2.5-Coder-32B-Instruct"
          : "Qwen/Qwen2.5-Coder-7B-Instruct",
        messages: [
          {
            content: message.prompt,
            role: "system",
          },
          {
            content: message.q,
            role: "user",
          },
        ],
      }),
    });

    if (!resp.ok) {
      throw new Error(`HTTP error! status: ${resp.status}`);
    }

    const data = await resp.json();
    if (data.choices && data.choices[0]?.message?.content) {
      return data.choices[0].message.content;
    }
    return "";
  } catch (error) {
    console.error("Error in handleCreateChatNonStream:", error);
    return "";
  }
}
